<template>
  <div class="recaptcha-container">
    <!-- v2版本显示复选框 -->
    <div v-if="version === 'v2'">
      <div :id="containerId" ref="recaptchaContainer"></div>
      <div v-if="error" class="recaptcha-error">{{ error }}</div>
    </div>
    
    <!-- v3版本不显示界面，在提交时静默验证 -->
    <div v-else-if="version === 'v3'" style="display:none;"></div>
    
    <!-- 加载中状态 -->
    <div v-if="loading" class="recaptcha-loading">
      <a-spin size="small" />
      <span>reCAPTCHA loading...</span>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';

const props = defineProps({
  // reCAPTCHA 站点密钥
  siteKey: {
    type: String,
    required: true
  },
  // 版本：v2 显示复选框, v3 隐形验证
  version: {
    type: String,
    default: 'v2',
    validator: (val) => ['v2', 'v3'].includes(val)
  },
  // 主题：light 或 dark
  theme: {
    type: String,
    default: 'light',
    validator: (val) => ['light', 'dark'].includes(val)
  },
  // 尺寸：normal, compact 或 invisible
  size: {
    type: String,
    default: 'normal',
    validator: (val) => ['normal', 'compact', 'invisible'].includes(val)
  },
  // 触发重置验证码的值，改变时会重置验证码
  resetTrigger: {
    type: [Boolean, Number, String],
    default: false
  }
});

const emit = defineEmits(['verified', 'expired', 'error', 'loaded']);

const recaptchaContainer = ref(null);
const widgetId = ref(null);
const containerId = `recaptcha-container-${Math.random().toString(36).substring(2, 8)}`;
const loading = ref(true);
const error = ref('');
const verifyToken = ref('');

// 加载 reCAPTCHA 脚本
const loadRecaptchaScript = () => {
  return new Promise((resolve, reject) => {
    // 检查脚本是否已加载
    if (window.grecaptcha) {
      resolve();
      return;
    }
    
    // 创建并添加脚本
    const script = document.createElement('script');
    script.src = `https://www.google.com/recaptcha/api.js?render=${props.version === 'v3' ? props.siteKey : 'explicit'}`;
    script.async = true;
    script.defer = true;
    
    script.onload = () => {
      // 给脚本一些时间初始化
      setTimeout(() => {
        resolve();
      }, 400);
    };
    
    script.onerror = (error) => {
      reject(new Error('Failed to load reCAPTCHA'));
    };
    
    document.head.appendChild(script);
  });
};

// 渲染验证码
const renderRecaptcha = () => {
  if (props.version === 'v2') {
    if (window.grecaptcha && window.grecaptcha.render) {
      try {
        // 如果已有实例，先重置
        if (widgetId.value !== null) {
          window.grecaptcha.reset(widgetId.value);
        } else {
          // 渲染新的验证码
          widgetId.value = window.grecaptcha.render(recaptchaContainer.value, {
            sitekey: props.siteKey,
            theme: props.theme,
            size: props.size,
            callback: onVerified,
            'expired-callback': onExpired,
            'error-callback': onError
          });
        }
        loading.value = false;
        emit('loaded');
      } catch (e) {
        error.value = 'Failed to load captcha, please refresh the page and try again';
        loading.value = false;
        emit('error', e);
      }
    }
  } else if (props.version === 'v3') {
    // v3版本静默加载
    loading.value = false;
    emit('loaded');
  }
};

// 验证成功回调
const onVerified = (token) => {
  verifyToken.value = token;
  error.value = '';
  emit('verified', token);
};

// 验证过期回调
const onExpired = () => {
  verifyToken.value = '';
  error.value = 'Verification expired, please verify again';
  emit('expired');
};

// 验证错误回调
const onError = (errorMessage) => {
  verifyToken.value = '';
  error.value = 'Verification error, please try again';
  emit('error', errorMessage);
};

// 执行v3验证
const executeRecaptchaV3 = (action = 'submit') => {
  return new Promise((resolve, reject) => {
    if (!window.grecaptcha || !window.grecaptcha.execute) {
      reject(new Error('reCAPTCHA not loaded'));
      return;
    }
    
    window.grecaptcha.ready(() => {
      window.grecaptcha.execute(props.siteKey, { action })
        .then((token) => {
          verifyToken.value = token;
          emit('verified', token);
          resolve(token);
        })
        .catch((error) => {
          emit('error', error);
          reject(error);
        });
    });
  });
};

// 重置验证码
const resetRecaptcha = () => {
  if (props.version === 'v2' && widgetId.value !== null && window.grecaptcha) {
    window.grecaptcha.reset(widgetId.value);
    verifyToken.value = '';
  }
};

// 公开方法
defineExpose({
  getToken: () => verifyToken.value,
  reset: resetRecaptcha,
  execute: (action) => props.version === 'v3' ? executeRecaptchaV3(action) : null
});

// 监听重置触发器
watch(() => props.resetTrigger, () => {
  resetRecaptcha();
});

// 组件挂载时加载验证码
onMounted(async () => {
  try {
    await loadRecaptchaScript();
    renderRecaptcha();
  } catch (e) {
    loading.value = false;
    error.value = 'Unable to load captcha, please check your network connection or refresh the page';
    emit('error', e);
  }
});

// 组件卸载前清理
onBeforeUnmount(() => {
  // 清理资源
});
</script>

<style scoped>
.recaptcha-container {
  margin: 10px 0;
}

.recaptcha-error {
  color: #ff4d4f;
  font-size: 12px;
  margin-top: 4px;
}

.recaptcha-loading {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #888;
  font-size: 12px;
}
</style> 

<!-- 
使用说明:

1. 引入组件:
   import GoogleRecaptcha from '@/components/GoogleRecaptcha.vue';

2. 在父组件中注册:
   components: {
     GoogleRecaptcha
   }

3. 在模板中使用:
   <template>
     <GoogleRecaptcha 
       ref="recaptchaRef"
       site-key="YOUR_RECAPTCHA_SITE_KEY" 
       @verified="handleVerified"
     />
   </template>

4. 在脚本中使用:
   <script setup>
   import { ref } from 'vue';
   import GoogleRecaptcha from '@/components/GoogleRecaptcha.vue';
   
   const recaptchaRef = ref(null);
   
   // 处理验证成功事件
   const handleVerified = (token) => {
     console.log('验证成功，令牌:', token);
     // 将token发送到后端进行验证...
   };
   
   // 对于v3版本，可以手动触发验证
   const verifyUser = async () => {
     if (recaptchaRef.value) {
       try {
         const token = await recaptchaRef.value.execute('login');
         // 使用token进行后续操作
       } catch (error) {
         console.error('reCAPTCHA验证失败:', error);
       }
     }
   };
   </script>

5. 参数说明:
   - siteKey: (String, 必填) Google reCAPTCHA站点密钥
   - version: (String, 默认: 'v2') reCAPTCHA版本，可选值: 'v2'或'v3'
     * v2: 显示复选框，用户需要点击"我不是机器人"
     * v3: 隐形验证，无需用户交互，通过调用execute方法获取token
   - theme: (String, 默认: 'light') 主题样式，可选值: 'light'或'dark'
   - size: (String, 默认: 'normal') 尺寸大小，可选值: 'normal', 'compact'或'invisible'
   - resetTrigger: (Boolean|Number|String, 默认: false) 当此值变化时，会触发验证码重置

6. 事件:
   - verified: 当验证成功时触发，返回验证token
   - expired: 当验证过期时触发
   - error: 当验证出错时触发，返回错误信息
   - loaded: 当reCAPTCHA加载完成时触发

7. 组件方法:
   - getToken(): 获取当前验证token
   - reset(): 重置验证码
   - execute(action): 仅适用于v3版本，执行验证并返回Promise，参数action为验证行为标识

8. 注意事项:
   - 使用v3版本时，需要在后端验证token的分数(score)，通常0.5以上视为人类操作
   - 确保您的网站域名已在Google reCAPTCHA管理后台注册
   - 在生产环境中使用时，请确保使用正确的站点密钥
   - 对于国内用户，可能需要考虑网络访问问题，建议提供备选验证方式
-->